package com.tvunetworks.center.device.service.impl;

import com.tvunetworks.center.common.constant.LocalConstant;
import com.tvunetworks.center.common.exception.ServerException;
import com.tvunetworks.center.common.model.CreateTRPairDto;
import com.tvunetworks.center.common.model.CreateTRPairList;
import com.tvunetworks.center.common.model.LoginUser;
import com.tvunetworks.center.common.model.dto.CheckAuthDTO;
import com.tvunetworks.center.common.model.dto.customizedcc.GroupUserAndRids;
import com.tvunetworks.center.common.model.param.GetIdleChannelParam;
import com.tvunetworks.center.common.model.param.UserServiceRegistDeviceParam;
import com.tvunetworks.center.common.model.param.customized.ExistUGCEventParam;
import com.tvunetworks.center.common.model.param.customized.RegistAnywhereAndPairRParam;
import com.tvunetworks.center.common.util.MyUtil;
import com.tvunetworks.center.common.util.Result;
import com.tvunetworks.center.common.util.ResultUtil;
import com.tvunetworks.center.device.mapper.MyDeviceMapper;
import com.tvunetworks.center.device.model.CustomizedUgcRecord;
import com.tvunetworks.center.device.model.MyDevice;
import com.tvunetworks.center.device.model.param.GetChannelParam;
import com.tvunetworks.center.device.model.result.ResultConstant;
import com.tvunetworks.center.device.service.*;
import com.tvunetworks.center.device.service.feign.*;
import com.tvunetworks.center.gs.model.Device;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * @program: tvucc-aggregator
 * @description: CustomizedCCServiceImpl
 * @author lebronchen
 * @create: 2020-04-14 14:02
 **/
@Service
@Slf4j
public class CustomizedCCServiceImpl implements CustomizedCCService {

    @Autowired
    private AccessFeignService accessFeignService;
    @Autowired
    private UserFeignService userFeignService;
    @Autowired
    private UserGroupFeignService userGroupFeignService;
    @Autowired
    private DeviceService deviceService;
    @Autowired
    private MyDeviceMapper myDeviceMapper;
    @Autowired
    private MyDeviceService myDeviceService;
    @Autowired
    private CustomizedUserFeignService customizedUserFeignService;
    @Autowired
    private BookingFeignService bookingFeignService;
    @Autowired
    private CustomizedLiveService customizedLiveService;
    @Autowired
    private TokenFeignService tokenFeignService;
    @Autowired
    private CustomizedUgcRecordService customizedUgcRecordService;

    @Value("${customized.ugc.anywhereType}")
    private String ugcAnywhereType;
    @Value("${customized.ugc.anywhereVersion}")
    private String ugcAnywhereVersion;
    @Value("${customized.ugcToken.validTime}")
    private long ugcTokenValidTime;
    @Value("${customized.ugcToken.removeOldPair}")
    private boolean ugcTokenRemoveOldPair;
    @Value("${customized.tokenType}")
    private String tokenType;


    @Override
    public String getChannel(GetChannelParam param) {

        // 格式化参数
        param.formate();

        // 校验参数
        this.getChannelCheckParam(param);

        // 校验 appkey
        this.getChannelCheckAppkey(param);

        // 校验 session
        String userId = this.getChannelCheckSession(param.getSession());

        // 自注册 anywhere
        Device pack = this.getChannelRegistDevice(param);

        String packId = param.getPackId();
        String ugcAccountId = param.getUgcAccountId();
        String group = param.getGroup();

        CustomizedUgcRecord ugcRecord = new CustomizedUgcRecord()
                .setUserId(userId)
                .setTid(packId)
                .setUgcAccountId(ugcAccountId)
                .setGroupName(group);

        GroupUserAndRids groupUserAndRids = customizedUserFeignService.getGroupUserAndRids(group);
        List<String> userIds = groupUserAndRids.getUserIds();
        // 校验 Group 是否存在
        if (CollectionUtils.isEmpty(userIds)) {
            Result result = ResultConstant.Group.NOT_EXIST;
            ugcRecord.setResult(result);
            customizedUgcRecordService.addRecord(ugcRecord);
            ServerException.Exception(result);
        }

        String rid = null;
        ExistUGCEventParam existUGCEventParam = new ExistUGCEventParam()
                .setUgcAccountId(ugcAccountId)
                .setPack(pack);
        Result<String> existUGCEventResult = bookingFeignService.existUGCEvent(existUGCEventParam);
        if (existUGCEventResult.assertSuccess()) {
            // 存在运行的 UGC booking，直接使用 booking 任务中的 rid
            rid = existUGCEventResult.getResult();
        } else {
            // 不存在运行的 UGC booking，重新获取一个可用的 r

            // 如果刚刚存在 getChannel 接口调用，并且返回的 r 可用，那么直接使用，不重新调用
            rid = this.checkUGCInterfaceRepeatCall(ugcAccountId, packId, userId);

            if (StringUtils.isBlank(rid)) {
                // 用户重复请求，不下发新 R
                GetIdleChannelParam idleChannelParam = new GetIdleChannelParam()
                        .setBooking(false)
                        .setUserId(userId)
                        .setGroupName(group);
                Device channel = customizedLiveService.getIdleChannel(idleChannelParam);
                if (channel == null) {
                    Result result = ResultUtil.error("80050008", "No available channel");
                    ugcRecord.setResult(result);
                    customizedUgcRecordService.addRecord(ugcRecord);
                    ServerException.Exception(result);
                }
                rid = channel.getPeerId();
            }
        }

        // 调用 tvucc-token 创建配对
        this.pairTR(rid, packId);

        ugcRecord.setRid(rid)
                .setResult(ResultUtil.success());
        customizedUgcRecordService.addRecord(ugcRecord);

        return rid;
    }

    @Override
    public void registAnywhereAndPairR(RegistAnywhereAndPairRParam param) {
        log.error("registAnywhereAndPairR param:{}", param);
        // 注册设备
        GetChannelParam getChannelParam = new GetChannelParam();
        BeanUtils.copyProperties(param, getChannelParam);
        getChannelRegistDevice(getChannelParam);

        // 创建配对
        pairTR(param.getRid(), param.getPackId());
        log.error("registAnywhereAndPairR success param:{}", param);
    }

    /**
     * 检查 UGC 接口调用是否被重复调用
     * 最近一次 UGC 接口调用返回的 rid 是否是可用的
     * @param ugcAccountId
     * @param packId
     * @param userId
     * @return
     */
    private String checkUGCInterfaceRepeatCall(String ugcAccountId, String packId, String userId){
        CustomizedUgcRecord existRecord = customizedUgcRecordService.getMostRecentUGCRecordByUGCAccountIdAndTid(ugcAccountId, packId);
        if (existRecord == null) {
            return null;
        }
        // 超过一定时间，重新获取可用通道
        if (System.currentTimeMillis() - existRecord.getCreateTime() > 1800000) {
            return null;
        }
        String rid = existRecord.getRid();
        if (StringUtils.isBlank(rid)) {
            return null;
        }
        // 如果上次获取的 channel， 现在变的不可用了，那么重新获取
        boolean channelIdle = customizedLiveService.isChannelIdle(userId, rid);
        if (!channelIdle) {
            return null;
        }
        return rid;
    }

    private void getChannelCheckParam(GetChannelParam param){
        if (!param.isNotCheckAccessApp()
                && (StringUtils.isEmpty(param.getAppkey())
                || StringUtils.isEmpty(param.getTimestamp())
                || StringUtils.isEmpty(param.getSignature()))) {
            ServerException.Exception(ResultUtil.paramErrorInfo());
        }
        if (StringUtils.isEmpty(param.getSession())
                || StringUtils.isEmpty(param.getPackId())
                || StringUtils.isEmpty(param.getUgcAccountId())
                || StringUtils.isEmpty(param.getGroup()) ) {
            ServerException.Exception(ResultUtil.paramErrorInfo());
        }
        if (param.getPackId().length() != 16) {
            ServerException.Exception(ResultConstant.Device.PACK_ID_LENGTH_MUST_16);
        }
    }

    private void getChannelCheckAppkey(GetChannelParam param){
        if (param.isNotCheckAccessApp()) {
            return;
        }
        CheckAuthDTO authDTO = new CheckAuthDTO()
                .setAppkey(param.getAppkey())
                .setTimestamp(param.getTimestamp())
                .setSignature(param.getSignature())
                .setIp(param.getIp())
                .setFunction("default");
        // 校验 appkey
        Result<Void> voidResult = accessFeignService.checkAuth(authDTO);
        if (!voidResult.assertSuccess()) {
            ServerException.Exception(voidResult);
        }
    }

    private String getChannelCheckSession(String session){
        Result<LoginUser> result = userFeignService.getLoginUserWithNoCheck(session);
        if (!result.assertSuccess()) {
            ServerException.Exception(ResultUtil.error("80050007", "Invalid session"));
        }
        LoginUser loginUser = result.getResult();
        if (loginUser == null) {
            ServerException.Exception(ResultUtil.error("80050007", "Invalid session"));
        }
        return loginUser.getId();
    }

    private Device getChannelRegistDevice(GetChannelParam param){
        String peerId = param.getPackId();
//        String ugcAccountId = param.getUgcAccountId();
        Device pack = deviceService.getCurrentDevice(peerId);
        if (pack == null) {

            // 自注册 anywhere
//            String name = null;
//            if (ugcAccountId.length() > 10) {
//                name = ugcAccountId.substring(ugcAccountId.length() - 10);
//            } else {
//                name = ugcAccountId;
//            }
//            name = name + "_" + peerId.substring(peerId.length() - 4);
            String name = myDeviceService.getNewDeviceName(peerId);
            String type = param.getDeviceType();
            if (StringUtils.isEmpty(type)) {
                type = ugcAnywhereType;
            }
            String version = param.getDeviceVersion();
            if (StringUtils.isEmpty(version)) {
                version = ugcAnywhereVersion;
            }
            UserServiceRegistDeviceParam registDeviceParam = new UserServiceRegistDeviceParam()
                    .setPeerId(peerId)
                    .setDeviceName(name)
                    .setDeviceType(type)
                    .setVersion(version);

            // 把设备插入到 tvu_device 表
            MyDevice anywhere = new MyDevice();
            BeanUtils.copyProperties(registDeviceParam, anywhere);
            anywhere.setType(LocalConstant.DeviceType.T)
                .setId(MyUtil.getUUID())
                    .setName(name);
            if (StringUtils.contains(type, "IOS")) {
                anywhere.setPlatform("10");
            } else if (StringUtils.contains(type, "MAC")) {
                anywhere.setPlatform("13");
            } else {
                // 默认设置为 Android
                anywhere.setPlatform("11");
            }
            myDeviceMapper.insert(anywhere);

            // 调用 user-group 接口注册设备
            Result<String> result = userGroupFeignService.registerDevice(registDeviceParam);
            if (!result.assertSuccess()) {
                log.error("userGroupFeignService.registerDevice failed param:{} result:{}", registDeviceParam, result);
                ServerException.Exception(ResultConstant.Device.REGIST_DEVICE_FAILED);
            }
            pack = deviceService.getCurrentDevice(peerId);
        }
        return pack;
    }

    @Override
    public void pairTR(String rid, String tid) {
        log.error("CustomizedCC pairTR rid:[{}] tid:[{}]", rid, tid);
        if (StringUtils.isBlank(rid) ||rid.length() != 16) {
            throw new ServerException(ResultUtil.paramErrorInfo().setResult("Invalid rid"));
        }
        if (StringUtils.isBlank(tid) ||tid.length() != 16) {
            throw new ServerException(ResultUtil.paramErrorInfo().setResult("Invalid tid"));
        }
        if (ugcTokenRemoveOldPair) {
            tokenFeignService.deleteAllTRPairByTidAndType(tid, tokenType);
        }

        List<CreateTRPairDto> list = new ArrayList<>();
        CreateTRPairDto dto = new CreateTRPairDto();
        dto.setRid(rid);
        dto.setTid(tid);
        dto.setValidTime(ugcTokenValidTime);
        list.add(dto);
        CreateTRPairList createTRPairParam = new CreateTRPairList();
        createTRPairParam.setTrPairList(list);
        createTRPairParam.setType(tokenType);
        try {
            Result<Object> result = tokenFeignService.createTRPair(createTRPairParam);
            if (!result.assertSuccess()) {
                log.error("tokenFeignService.createTRPair result not success");
                ServerException.Exception(ResultUtil.error("80050013", "Add token failed"));
            }
        } catch (Exception e) {
            log.error("tokenFeignService.createTRPair exception");
            log.error(e.toString(), e);
            ServerException.Exception(ResultUtil.error("80050013", "Add token failed"));
        }

    }

}
